package com.tanhua.server.service;

import com.alibaba.fastjson.JSON;
import com.tanhua.commons.templates.OssTemplate;
import com.tanhua.domain.db.UserInfo;
import com.tanhua.domain.mongo.Comment;
import com.tanhua.domain.mongo.Publish;
import com.tanhua.domain.mongo.Visitors;
import com.tanhua.domain.vo.FreeZe;
import com.tanhua.domain.vo.MovementsVo;
import com.tanhua.domain.vo.PageResult;
import com.tanhua.domain.vo.VisitorsVo;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.dubbo.api.mongo.CommentApi;
import com.tanhua.dubbo.api.mongo.PublishApi;
import com.tanhua.dubbo.api.mongo.RecommendUserApi;
import com.tanhua.dubbo.api.mongo.VisitorsApi;
import com.tanhua.server.interceptor.UserHolder;
import com.tanhua.server.utils.RelativeDateFormat;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class MovementsService {



    @Autowired
    private OssTemplate ossTemplate;

    @Reference
    private PublishApi publishApi;


    @Reference
    private UserInfoApi userInfoApi;

    @Reference
    private CommentApi commentApi;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Reference
    private VisitorsApi visitorsApi;


    @Reference
    private RecommendUserApi recommendUserApi;


    @Autowired(required = false)
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private MovementsMQService movementsMQService;


    /**
     * 发布动态
     * @param publish  动态()
     * @param imageContent  动态的图片（朋友圈的图片）
     * @return
     */
    public ResponseEntity saveMovements(Publish publish, MultipartFile[] imageContent) throws IOException {
        //1. 得到当前登陆者id
        Long userId = UserHolder.getUserId();
        //              禁止发动态
        String freezekey="FREEZE_KEY_"+UserHolder.getUserId();
        String freeZEString = redisTemplate.opsForValue().get(freezekey);


        FreeZe freeZe = JSON.parseObject(freeZEString, FreeZe.class);
        if(freeZe!=null) {
            if (freeZe.getFreezingRange() == 3) {

                String reasons = freeZe.getReasonsForFreezing();
                //        秒数
                Long expire = redisTemplate.opsForValue().getOperations().getExpire(freezekey);
//            -1永久冻结 -2没有此键
                String day = null;
                if (expire != -1) {
                    day = "还要冻结" + expire / 60 / 60 / 24 + "天"+expire+"秒";
                } else {
                    day = "永久冻结";
                }
                return ResponseEntity.status(404).body(day + "原因:" + reasons);
            }
        }
        //2. 把动态的图片上传到阿里云存储 ossTemplate
        List<String> medias = new ArrayList<>();
        if(imageContent!=null&&imageContent.length>0){
            for (MultipartFile multipartFile : imageContent) {
                String picUrl = ossTemplate.upload(multipartFile.getOriginalFilename(), multipartFile.getInputStream());
                //上传完毕的图片把路径存储到集合中
                medias.add(picUrl);
            }
        }
        //3. 补全publish的信息
        publish.setUserId(UserHolder.getUserId()); //谁发送的朋友圈
        publish.setMedias(medias); //图片的路径
        publish.setCreated(System.currentTimeMillis()); //

        publish.setState(0);//内容还没有经过审核
        publish.setId(ObjectId.get());
        //4. 保存到数据库中
        publishApi.save(publish);

        //往rocketmq发送消息
        rocketMQTemplate.convertAndSend("tanhua-publish",publish.getId().toString());
        //往rocketmq发送推荐信息记录给大数据团队去使用
        movementsMQService.publishMsg(publish.getId().toString());

        //5. 返回响应
        return ResponseEntity.ok(null);

    }


    /**
     * 查询好友动态
     * @param page
     * @param pagesize
     * @return
     */
    public ResponseEntity queryPublishList(Integer page, Integer pagesize) {
        //1. 得到当前的登陆者的id
        Long userId = UserHolder.getUserId();

        //2. 通过查询时间线表得到好友的动态分页对象  PageResult  pageresult存储的是publish
        PageResult pageResult = publishApi.findByTimeLine(page,pagesize,userId);
        setMoveMentsVo(pageResult);


        //7. 返回响应
        return ResponseEntity.ok(pageResult);
    }

    //作用： 把publish转换为MoveMentVo对象，并且voList存储到pageResult
    private void setMoveMentsVo(PageResult pageResult) {
        //3. 得到pageReuslt的Items  List<publish>
        List<Publish> publishList = (List<Publish>) pageResult.getItems();

        //4. 创建一个Vo集合  List<MovementsVo>
        List<MovementsVo> voList = new ArrayList<>();

        //5. 遍历publish的list，转换为movements
        if(publishList!=null){
            for (Publish publish : publishList) {
                MovementsVo vo = new MovementsVo();
                UserInfo userInfo = userInfoApi.findById(publish.getUserId());
                // userInfo信息
                if(userInfo!=null){
                    BeanUtils.copyProperties(userInfo,vo);
                    //用户的标签
                    if(userInfo.getTags()!=null){
                        vo.setTags(userInfo.getTags().split(","));
                    }
                }
                vo.setUserId(userInfo.getId());

                BeanUtils.copyProperties(publish,vo);
                //动态的信息
                vo.setId(publish.getId().toString());
                vo.setImageContent(publish.getMedias().toArray(new String[]{})); //动态图片
                vo.setDistance("50米");
                vo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated()))); //动态的发布时间

                String likeKey  ="publish_like_comment_"+UserHolder.getUserId()+"_"+publish.getId();
                if(redisTemplate.hasKey(likeKey)){
                    vo.setHasLiked(1); //你是否已经对该朋友圈点赞
                }else {
                    vo.setHasLiked(0); //你是否已经对该朋友圈点赞
                }
                String loveKey  ="publish_love_comment_"+UserHolder.getUserId()+"_"+publish.getId();
                if(redisTemplate.hasKey(loveKey)){
                    vo.setHasLoved(1);  //你是否喜欢该朋友圈
                }else {
                    vo.setHasLoved(0);  //你是否喜欢该朋友圈
                }
                //把vo添加到集合中
                voList.add(vo);
            }
        }
        //6. 把volist存储到pageResult对象中
        pageResult.setItems(voList);
    }

    /**
     * 查询推荐的动态
     * @param page  当前页
     * @param pagesize  页面大小
     * @return
     */
    public ResponseEntity queryRecommendPublishList(Integer page, Integer pagesize) {
        //1. 得到当前的登陆者的id
        Long userId = UserHolder.getUserId();
        //2. 通过查询recommend_quanzi推荐动态表，得到分页对象， 分页对象中还是存储了publish
        PageResult pageResult = findByRecommend(page, pagesize);; //从redis中查找数据，如果redis中没有该用户推荐的数据，才查询数据库
        if(pageResult==null) {
            pageResult = publishApi.queryRecommendPublishList(page, pagesize, userId);
        }
        setMoveMentsVo(pageResult);
        //3. 返回响应对象
        return ResponseEntity.ok(pageResult);
    }

    /**
     *  从redis中查找当前当前用户的推荐圈子的信息
     * @param page
     * @param pagesize
     * @return
     */
    private PageResult findByRecommend(Integer page, Integer pagesize) {
        //1. 先从reids中取出推荐的数据
        String key = "QUANZI_PUBLISH_RECOMMEND_"+UserHolder.getUserId();
        String value = redisTemplate.opsForValue().get(key);
        //2. 判断是否为空,如果为null直接返回null
        if(value==null){
            //该用户没有推荐的信息
            return null;
        }
        String[] pidList = value.split(",");
        //3.计算startIndex、endIndex， startIndex开始取索引值， endIndex结束的索引值
        int startIndex = (page-1)*pagesize;
        if(startIndex<pidList.length){
            int endIndex = startIndex+pagesize-1;
            if(endIndex>=pidList.length){
                endIndex = pidList.length-1;
            }
            //4.把当前页面的pid存储到集合中查询对应的publish存储到集合中
            List<Long> pList = new ArrayList<>(); // 33,7,36,36,14,38,31
            for (int i = startIndex; i <=endIndex ; i++) {
                pList.add(Long.valueOf(pidList[i]));
            }

            //根据pList查找publish
            List<Publish> publishList = publishApi.findByPids(pList);
            PageResult pageResult = new PageResult(page,pagesize,pidList.length,publishList);
            return pageResult;

        }
        //5. 返回pageREsult;
        return  null;
    }


    /**
     * 点赞
     * @param publishId  动态的id
     * @return
     */
    public ResponseEntity likeComment(String publishId) {
        //1. 获取登陆者的id
        Long userId = UserHolder.getUserId();
        //2. 创建Comment,补全的信息
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));
        comment.setCommentType(1); //评论的类型， 1. 点赞 2 评论  3 喜欢
        comment.setPubType(1); //评论内容类型： 1. 朋友圈 2 视频  3.评论
        comment.setUserId(userId);
        comment.setLikeCount(0);//注意：这个是评论的点赞数，不是动态的点赞数据，而且该功能我们没有实现
        comment.setCreated(System.currentTimeMillis());
        //3.插入一个评论的记录 ,对点赞的朋友圈的点赞数+1,并且返回最新的点赞数
        Integer likeCount =  commentApi.save(comment);

        //4.设置一个标记,让手指头高亮
        String likeKey  ="publish_like_comment_"+UserHolder.getUserId()+"_"+publishId;
        redisTemplate.opsForValue().set(likeKey,"1");

        //发送消息给rocketmq
        movementsMQService.likePublishMsg(publishId);


        //5.返回点赞数
        return ResponseEntity.ok(likeCount);
    }

    /**
     * 取消点赞
     * @param publishId
     * @return
     */
    public ResponseEntity dislikeComment(String publishId) {
        //1. 获取登陆者的id
        Long userId = UserHolder.getUserId();
        //2. 创建Comment,补全的信息
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));
        comment.setCommentType(1); //评论的类型， 1. 点赞 2 评论  3 喜欢
        comment.setPubType(1); //评论内容类型： 1. 朋友圈 2 视频  3.评论
        comment.setUserId(userId);
        //3.删除评论
        Integer likeCount =  commentApi.delete(comment);

        //4.设置一个标记,让手指头高亮
        String likeKey  ="publish_like_comment_"+UserHolder.getUserId()+"_"+publishId;
        redisTemplate.delete(likeKey);

        //5.返回点赞数
        return ResponseEntity.ok(likeCount);
    }

    /**
     * 喜欢
     * @param publishId
     * @return
     */
    public ResponseEntity loveComment(String publishId) {
        //1. 获取登陆者的id
        Long userId = UserHolder.getUserId();
        //2. 创建Comment,补全的信息
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));
        comment.setCommentType(3); //评论的类型， 1. 点赞 2 评论  3 喜欢
        comment.setPubType(1); //评论内容类型： 1. 朋友圈 2 视频  3.评论
        comment.setUserId(userId);
        comment.setLikeCount(0);//注意：这个是评论的点赞数，不是动态的点赞数据，而且该功能我们没有实现
        comment.setCreated(System.currentTimeMillis());
        //3.插入一个评论的记录 ,对点赞的朋友圈的点赞数+1,并且返回最新的点赞数
        Integer loveCount =  commentApi.save(comment);

        //4.设置一个标记,让手指头高亮
        String loveKey  ="publish_love_comment_"+UserHolder.getUserId()+"_"+publishId;
        redisTemplate.opsForValue().set(loveKey,"1");


        //5.返回点赞数
        return ResponseEntity.ok(loveCount);
    }

    //取消喜欢
    public ResponseEntity unloveComment(String publishId) {
        //1. 获取登陆者的id
        Long userId = UserHolder.getUserId();
        //2. 创建Comment,补全的信息
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));
        comment.setCommentType(3); //评论的类型， 1. 点赞 2 评论  3 喜欢
        comment.setPubType(1); //评论内容类型： 1. 朋友圈 2 视频  3.评论
        comment.setUserId(userId);
        //3.删除评论
        Integer loveCount =  commentApi.delete(comment);

        //4.设置一个标记,让手指头高亮
        String loveKey  ="publish_love_comment_"+UserHolder.getUserId()+"_"+publishId;
        redisTemplate.delete(loveKey);

        //5.返回点赞数
        return ResponseEntity.ok(loveCount);
    }

    /**
     * 查询单条动态
     * @param publishId
     * @return
     */
    public ResponseEntity queryMovementsById(String publishId) {
        //1. 根据动态的id查找动态  Publish
        Publish publish = publishApi.findById(publishId);

        //2.创建一个MovementVo
        MovementsVo vo = new MovementsVo();
        UserInfo userInfo = userInfoApi.findById(publish.getUserId());
        // userInfo信息
        if(userInfo!=null){
            BeanUtils.copyProperties(userInfo,vo);
            //用户的标签
            if(userInfo.getTags()!=null){
                vo.setTags(userInfo.getTags().split(","));
            }
        }
        vo.setUserId(userInfo.getId());

        BeanUtils.copyProperties(publish,vo);
        //动态的信息
        vo.setId(publish.getId().toString());
        vo.setImageContent(publish.getMedias().toArray(new String[]{})); //动态图片
        vo.setDistance("50米");
        vo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated()))); //动态的发布时间

        String likeKey  ="publish_like_comment_"+UserHolder.getUserId()+"_"+publish.getId();
        if(redisTemplate.hasKey(likeKey)){
            vo.setHasLiked(1); //你是否已经对该朋友圈点赞
        }else {
            vo.setHasLiked(0); //你是否已经对该朋友圈点赞
        }
        String loveKey  ="publish_love_comment_"+UserHolder.getUserId()+"_"+publish.getId();
        if(redisTemplate.hasKey(loveKey)){
            vo.setHasLoved(1);  //你是否喜欢该朋友圈
        }else {
            vo.setHasLoved(0);  //你是否喜欢该朋友圈
        }

        //4. 返回响应
        return ResponseEntity.ok(vo);

    }


    /**
     * 接口名称：用户动态
     */
    public ResponseEntity<Object> queryMyPublishList(Integer page, Integer pagesize, Long userId) {
        // 1.获取登录用户id
        if (userId == null) {
            // 如果未传入userId，就获取当前用户id
            userId = UserHolder.getUserId();
        }

        // 2.调用服务提供者分页查询该用户的个人动态
        PageResult pageResult = publishApi.queryMyPublishList(page, pagesize, userId);

        // 3.调用公共方法，设置返回结果
        setMovementsVo(pageResult);

        return ResponseEntity.ok(pageResult);
    }

    /**
     * 好友动态及推荐动态公共方法
     */
    public void setMovementsVo(PageResult pageResult) {

        // 获取当前页的数据
        List<Publish> publishList = (List<Publish>) pageResult.getItems();

        // 3.封装返回结果
        List<MovementsVo> voList = new ArrayList<>();

        if (publishList != null) {
            for (Publish publish : publishList) {
                // 3.1 创建vo对象
                MovementsVo vo = new MovementsVo();
                // 3.2 查询用户详情信息
                UserInfo userInfo = userInfoApi.findById(publish.getUserId());
                // 3.3 封装用户信息
                if (userInfo != null) {
                    BeanUtils.copyProperties(userInfo, vo);
                    if (userInfo.getTags() != null) {
                        vo.setTags(userInfo.getTags().split(","));
                    }
                }

                // 3.4 封装动态信息
                BeanUtils.copyProperties(publish, vo);
                if (publish.getMedias() != null) {
                    vo.setImageContent(publish.getMedias().toArray(new String[]{}));
                }

                // 3.5 封装其他参数
                vo.setDistance("50米");
                vo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated()))); // 转换时间（1小时之前）
                vo.setId(publish.getId().toString());
                vo.setHasLiked(0);
                vo.setHasLoved(0);

                // 3.6 添加vo对象
                voList.add(vo);
            }
        }
        pageResult.setItems(voList);
    }

    /**
     * 谁看过我
     * @return
     */
    public ResponseEntity<Object> queryVisitors() {
        //1. 记录上一次该用户进入首页的时间的key
        String key = "visitors_time_" + UserHolder.getUserId();
        List<Visitors> visitorsList =null;
        if(!redisTemplate.hasKey(key)){
            //没有记录该用户上一次访问时间的(首次登陆或者记录的时间失效了)
            visitorsList = visitorsApi.queryVisitors(UserHolder.getUserId(),5,null);
        }else{
            //有记录该用户上一次访问时间的
            long lastTime = Long.parseLong(redisTemplate.opsForValue().get(key));
            visitorsList = visitorsApi.queryVisitors(UserHolder.getUserId(),5,lastTime);
        }

        //2.更新用户上次进入该页面的时间
        redisTemplate.opsForValue().set(key,System.currentTimeMillis()+"");

        //3. 创建VoList，把visitorsList转换为voList
        List<VisitorsVo> voList = new ArrayList<>();
        if(visitorsList!=null){
            for (Visitors visitors : visitorsList) {
                VisitorsVo vo  = new VisitorsVo();
                //查找userInfo信息
                UserInfo userInfo = userInfoApi.findById(visitors.getVisitorUserId());
                if(userInfo!=null){
                    BeanUtils.copyProperties(userInfo,vo);
                    if(userInfo.getTags()!=null){
                        vo.setTags(userInfo.getTags().split(","));
                    }
                    //设置缘分值
                    Long score = recommendUserApi.queryScore(UserHolder.getUserId(), visitors.getVisitorUserId());
                    vo.setFateValue(score.intValue());
                    voList.add(vo);
                }
            }
        }
        return ResponseEntity.ok(voList);
    }
}
